package com.suray.wcs.service.thread.process;

import com.suray.basic.wcs.path.enums.NodeStatus;
import com.suray.basic.wcs.plc.core.Plc;
import com.suray.basic.wcs.plc.enums.CargoState;
import com.suray.basic.wcs.plc.enums.PlcDeviceType;
import com.suray.basic.wcs.plc.pojo.oper.single.DeviceInterface;
import com.suray.basic.wcs.plc.utils.PlcTaskType;
import com.suray.basic.wcs.plc.utils.PlcUnit;
import com.suray.basic.wcs.utils.LoggerUtil;
import com.suray.basic.wcs.utils.WcsFuncUtil;
import com.suray.commin.core.utils.SpringContextHolder;
import com.suray.wcs.service.enums.DetailProcess;
import com.suray.wcs.service.enums.PrecessStatus;
import com.suray.wcs.service.system.entity.TaskDB;
import com.suray.wcs.service.system.entity.TaskDetailDB;
import com.suray.wcs.service.system.service.impl.NodeDBServiceImpl;
import com.suray.wcs.service.system.service.impl.TaskDBServiceImpl;
import com.suray.wcs.service.system.service.impl.TaskDetailServiceImpl;

import java.io.IOException;

public class PlcConveryTask {

    private static TaskDBServiceImpl taskdbServiceImpl = SpringContextHolder.getBean(TaskDBServiceImpl.class);
    private static NodeDBServiceImpl nodeService = SpringContextHolder.getBean(NodeDBServiceImpl.class);
    private static TaskDetailServiceImpl taskDetailService = SpringContextHolder.getBean(TaskDetailServiceImpl.class);

    public static int analyzePlcTaskNo(int taskNo, PlcTaskType taskType) {
        if (taskType == null) {
            return taskNo;
        }

        if (taskNo >= 10000) {
            throw new RuntimeException("Plc任务编号错误，任务编号必须小于10000");
        }

        switch (taskType) {
            case REMOVE_PALLET:
            case STACK_PALLET:
            case ALL_IN:
            case ALL_OUT:
                return taskType.getValue() * 10000 + taskNo;
            default:
                break;
        }

        return taskNo;
    }

    /**
     * 单体输送线任务
     * @param startDevice
     * @param endDevice
     * @param taskDB
     * @param stationTask
     * @throws IOException
     */
    public static void plcTransCargo(DeviceInterface startDevice, DeviceInterface endDevice, TaskDB taskDB,
                                     TaskDetailDB stationTask)
            throws IOException {
        TaskDetailDB taskDetail = null;
        int plcId = taskDB.getPlcId();
        if (taskDB.getSubTaskType() != null) {
            plcId = analyzePlcTaskNo(plcId, PlcTaskType.parseValue(taskDB.getSubTaskType()));
        }
        //起点设备写入任务信息
        try {
            TaskDetailDB taskDetailDB = taskDetailService.getTaskDetail(taskDB.getTaskId(),
                        DetailProcess.STATION_INSTRUCTION, stationTask.getUuid(), startDevice.getDeviceName(),
                        endDevice.getDeviceName(), PrecessStatus.CONDUCT, null, null);
            startDevice.sendConveryTask(plcId, startDevice.getDeviceNo(), endDevice.getDeviceNo());
            taskDetailService.updateTaskDetailCompleteTime(taskDetailDB);
            taskDetail = taskDetailService.getTaskDetail(taskDB.getTaskId(), DetailProcess.STATION_RUN,
                    stationTask.getUuid(), startDevice.getDeviceName(), endDevice.getDeviceName(),
                    PrecessStatus.CONDUCT, null, null);
        } catch (Exception e) {
            WcsFuncUtil.exceptionLog(e, PlcConveryTask.class);
            LoggerUtil.info("输送指令下发出现异常" + e.getMessage(), PlcConveryTask.class);
        }
        //任务完成验证
        checkConveyTaskFinish(endDevice, plcId, taskDB, 120);
        assert taskDetail != null;
        taskDetailService.updateTaskDetailCompleteTime(taskDetail);
    }

    public static void plcTransCargo(DeviceInterface startDevice, DeviceInterface endDevice, PlcTaskType plcTaskType,
                                     int plcId) throws IOException {
        plcTransCargo(startDevice, endDevice, plcTaskType, plcId, 120);
    }

    /**
     * 单体输送线任务
     * @param startDevice
     * @param endDevice
     * @param plcTaskType
     * @param plcId
     * @param timeOut
     * @throws IOException
     */
    public static void plcTransCargo(DeviceInterface startDevice, DeviceInterface endDevice, PlcTaskType plcTaskType,
                                     int plcId, int timeOut) throws IOException {
        plcId = analyzePlcTaskNo(plcId, plcTaskType);
        //起点设备写入任务信息
        startDevice.sendConveryTask(plcId, startDevice.getDeviceNo(), endDevice.getDeviceNo());
        //任务完成验证
        checkConveyTaskFinish(endDevice, plcId, null, timeOut);
    }

    private static void checkConveyTaskStatus(DeviceInterface device, Integer plcId, TaskDB taskDB) throws IOException {
        LoggerUtil.info("等待设备 " + device.getDeviceName() + "的" + plcId + "号任务离开起始工位",
                PlcConveryTask.class);
        while (plcId.equals(device.getTaskNo()) || device.hasCargo() || device.isRunning()) {
            device.setDeviceStatus("等待货物离开:" + plcId);
            if (taskDB != null) {
                Plc.checkPLCInterrupt(taskDB.getTaskId().toString(), "checkConveyTaskStatus");
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        device.setDeviceStatus("");
        nodeService.updateNodeDBStatus(device.getCoord(), NodeStatus.N.toString());
        PlcUnit.writeTwoDirectionRgvCargoState(device.getCoord(), CargoState.No_CARGO);
        LoggerUtil.info("设备 " + device.getDeviceName() + "的" + plcId +
                        "号任务离开起始工位，更新货位状态为无货", PlcConveryTask.class);
    }

    private static void checkConveyTaskFinish(DeviceInterface device, Integer plcId, TaskDB taskDB, int timeOut)
            throws IOException {
        LoggerUtil.info("等待设备 " + device.getDeviceName() + "的" + plcId + "号任务完成", PlcConveryTask.class);
        while (true) {
            if (device.getPlcDeviceType() == PlcDeviceType.FOLDING_MACHINE) {
                if (!(!plcId.equals(device.getTaskNo()) || device.isRunning()
                        || !device.getTaskEndLocation().equals(device.getDeviceNo()))) {
                    break;
                }
            } else {
                if (!(!plcId.equals(device.getTaskNo()) || !device.hasCargo() || device.isRunning()
                        || !device.getTaskEndLocation().equals(device.getDeviceNo()))) {
                    break;
                }
            }
            device.setDeviceStatus("等待货物到达终点：" + plcId);
            if (taskDB != null) {
                Plc.checkPLCInterrupt(taskDB.getTaskId().toString(), "checkConveyTaskFinish");
            } else {
                if (timeOut > 0) {
                    timeOut--;
                } else {
                    throw new RuntimeException(plcId + "号任务执行超时");
                }
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        device.setDeviceStatus("任务完成，清除任务信息");
        device.clearTaskNo();
        device.setDeviceStatus("");
        LoggerUtil.info("设备 " + device.getDeviceName() + "的" + plcId + "号任务完成", PlcConveryTask.class);
    }
}
